package com.example.myapplication;

import android.content.Context;
import android.os.Environment;
import android.util.Log;

import com.base.core.EmptyUtils;
import com.base.core.NetUtils;
import com.base.core.config.DefalutSp;
import com.base.core.net.HttpLogger;
import com.base.core.net.RetrofitClient;
import com.base.core.net.SSlUtils;
import com.base.core.ui.BaseCore;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;

import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

import static com.base.core.ui.mvp.WebSettingUtil.getCacheFilePath;

public class Retrofit2Client {
    private static final String TAG = "RetrofitClient";
    private static Retrofit retrofit = null;
    public static final int READ_TIMEOUT = 60;
    public static final int WRIT_TIMEOUT = 60;
    public static final int CONNECT_TIMEOUT = 16;
    public static String baseUrl = "http://";
    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
            .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)//设置读取超时时间
            .writeTimeout(WRIT_TIMEOUT, TimeUnit.SECONDS)//设置写的超时时间
            .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);

    public static Retrofit getClient() {
        if (retrofit == null) {
            synchronized (RetrofitClient.class) {
                if (retrofit == null) {
                    retrofit = new Retrofit.Builder()
                            .baseUrl(baseUrl)
                            .addConverterFactory(LenientGsonConverterFactory.create())
                            .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //适配rxjava2.0
                            .client(getOkHttpClient())
                            .build();
                }
            }
        }
        return retrofit;
    }

    public static void init(String Url) {
        baseUrl = Url;
        retrofit = null;
    }

    public static <T> T createApi(Class<T> clazz) {
        return getClient().create(clazz);
    }


    public static OkHttpClient getOkHttpClient() {
        SSLSocketFactory sslContext = SSlUtils.getUnsafeOkHttpClient();
        //缓存
        File cacheFile = new File(getCacheFile(BaseCore.app, false), "httpCache");
        Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb
        OkHttpClient client = httpClient
                // 日志拦截器
                .addInterceptor(new HttpLoggingInterceptor(new HttpLogger()).setLevel
                        (HttpLoggingInterceptor.Level.BODY))
                .addNetworkInterceptor(cacheInterceptor)
                .addInterceptor(cacheInterceptor)
                .addInterceptor(new RetrofitClient.TokenInterceptor())
                .cache(cache)
                .addInterceptor(setCommonParams())
                .sslSocketFactory(sslContext)
                .hostnameVerifier(new RetrofitClient.TrustAllHostnameVerifier())
                .build();
        return client;
    }

    public static Interceptor setCommonParams() {
        return new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request original = chain.request();
                Request.Builder builder = original.newBuilder();
                if (!EmptyUtils.isEmpty(DefalutSp.getToken())) {
                    builder.addHeader("Authorization", "Bearer " + DefalutSp.getToken());
                    Log.d(TAG,DefalutSp.getToken());

                }
                Request request = builder.build();

                return chain.proceed(request);
            }
        };
    }


    public static Interceptor cacheInterceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            int maxAge = 60 * 60; // 有网络时 设置缓存超时时间1个小时
            int maxStale = 60 * 60 * 24 * 28; // 无网络时，设置超时为4周
            Request request = chain.request();
            if (NetUtils.netIsConnected(BaseCore.app)) {
                request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_NETWORK)//有网络时只从网络获取
                        .build();
            } else {
                request = request.newBuilder()
                        .cacheControl(CacheControl.FORCE_CACHE)//无网络时只从缓存中读取
                        .build();
            }
            Response response = chain.proceed(request);
            if (NetUtils.netIsConnected(BaseCore.app)) {
                response = response.newBuilder()
                        .removeHeader("Pragma")
                        .header("Cache-Control", "public, max-age=" + maxAge)
                        .build();
            } else {
                response = response.newBuilder()
                        .removeHeader("Pragma")
                        .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                        .build();
            }
            return response;

        }
    };

    public static class TrustAllHostnameVerifier implements HostnameVerifier {

        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

    public static class TokenInterceptor implements Interceptor {

        private final Charset UTF8 = Charset.forName("UTF-8");

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            // try the request
            Response originalResponse = chain.proceed(request);
            /**通过如下的办法曲线取到请求完成的数据
             *
             * 原本想通过  originalResponse.body().string()
             * 去取到请求完成的数据,但是一直报错,不知道是okhttp的bug还是操作不当
             *
             * 然后去看了okhttp的源码,找到了这个曲线方法,取到请求完成的数据后,根据特定的判断条件去判断token过期
             */
            if (originalResponse.code() == 401) {//根据和服务端的约定判断token过期

            }
            return originalResponse;
        }
    }
    /**
     * 返回缓存文件夹
     *
     * @param context
     * @param isExternalCache 是否是sd卡缓存路径
     * @return
     */
    public static File getCacheFile(Context context, boolean isExternalCache) {
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) && isExternalCache) {
            File file = null;
            file = context.getExternalCacheDir();//获取系统管理的sd卡缓存文件
            if (file == null) {//如果获取的为空,就是用自己定义的缓存文件夹做缓存路径
                file = new File(getCacheFilePath(context));
                if (!file.exists()) {
                    file.mkdirs();
                }
            }
            return file;
        } else {
            return context.getCacheDir();// 获取app缓存目录，glide就是默认缓存在这儿的
        }
    }
}
